namespace TransformCodeGenerator
{
  using System;
  using Microsoft.Win32;
  using System.Runtime.InteropServices;
  using Microsoft.VisualStudio.TextTemplating.VSHost;

  /// <summary>
  /// Inheriter must supply the GuidAttribute and CustomToolAttribute 
  /// </summary>
  public abstract class CustomToolBase: BaseCodeGeneratorWithSite
  {

    #region Static Section

    internal const string VS_VERSION = "9.0";

    internal static Guid CSharpCategoryGuid = new Guid("FAE04EC1-301F-11D3-BF4B-00C04F79EFBC");

    // TODO: enhance to support VB.NET

    [ComRegisterFunction]
    public static void RegisterClass(Type t)
    {
      GuidAttribute guidAttribute = getGuidAttribute(t);
      CustomToolAttribute customToolAttribute = getCustomToolAttribute(t);
      using( RegistryKey key = Registry.LocalMachine.CreateSubKey(GetKeyName(CSharpCategoryGuid, customToolAttribute.Name)))
      {
        if (key == null)
          throw new Exception("Visual Studio 2008 isn't installed.");

        key.SetValue("", customToolAttribute.Description);
        key.SetValue("CLSID", "{" + guidAttribute.Value + "}");
        key.SetValue("GeneratesDesignTimeSource", 1);
      }
    }

    [ComUnregisterFunction]
    public static void UnregisterClass(Type t)
    {
      CustomToolAttribute customToolAttribute = getCustomToolAttribute(t);
      Registry.LocalMachine.DeleteSubKey(GetKeyName(CSharpCategoryGuid, customToolAttribute.Name), false);
    }

    internal static GuidAttribute getGuidAttribute(Type t)
    {
      return (GuidAttribute)getAttribute(t, typeof(GuidAttribute));
    }

    internal static CustomToolAttribute getCustomToolAttribute(Type t)
    {
      return (CustomToolAttribute)getAttribute(t, typeof(CustomToolAttribute));
    }

    internal static Attribute getAttribute(Type t, Type attributeType)
    {
      object[] attributes = t.GetCustomAttributes(attributeType, /* inherit */ true);
      if(attributes.Length==0)
        throw new Exception(String.Format("Class '{0}' does not provide a '{1}' attribute.", t.FullName, attributeType.FullName));
      return (Attribute)attributes[0];
    }

    internal static string GetKeyName(Guid categoryGuid, string toolName)
    {
      return String.Format("SOFTWARE\\Microsoft\\VisualStudio\\{0}\\Generators\\{{{1}}}\\{2}\\", VS_VERSION, categoryGuid.ToString(), toolName);
    }

    #endregion

    protected CustomToolBase()
    {
    }

    protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
    {
      string returnString = this.DoGenerateCode(inputFileName, inputFileContent);
      return System.Text.Encoding.ASCII.GetBytes(returnString);
    }

    public abstract string DoGenerateCode(string inputFileName, string inputFileContent);

  }
}
